﻿package src.computation 
{	
	/**
	* 
	* Reliability project
	* -----------------------
	* @author  Dmitrij Boycov
	* @mail    dmitry.boycov@gmail.com
	* @date    April 27, 2010
	* @version 1
	* 
	*/
	
	import flash.utils.Dictionary;
	import src.util.Utils;
	
	public class TimeLine {
		
		private var maxTime;
		private var currentTime = 0;
		private const WORK:String = "work";
		private const RECOVERY:String = "recovery";
		/**
		 * times is dictionare which each item is:
		 * 	{ type: "work"/"recovery", 
		 * 	  t0: start of time interval,
		 * 	  te: end of interval
		 * 	}
		 * 	key is t0;
		 */
		private var times:Dictionary;
		
		/**
		 * construct
		 * @param	maxtime = 0
		 */
		public function TimeLine(maxtime = 0) {
			this.maxTime = maxtime;
			this.times = new Dictionary(true);
		}
		
		public function setMaxTime(maxTime) {
			this.maxTime = maxTime;
		}
		
		public function getMaxTime() {
			return maxTime;
		}
		
		public function getCurrentTime() {
			return this.currentTime;
		}
		
		private function addTime(type,t):Boolean {
			if (this.currentTime < this.maxTime) {
				if (t < 0) { 
					// t = -1 is mins that element is not recovered
					// And time of recovered equal rest system work time
					this.times[this.currentTime] = { type:type, t0:this.currentTime, te: this.maxTime } ;
					this.currentTime = this.maxTime;
					return true;
				}else{
					this.times[this.currentTime] = { type:type, t0:this.currentTime, te: this.currentTime + t};
					this.currentTime += t;
					return true;
				}
			}
			return false;
		}
		
		public function addWorKTime(t):Boolean {
			return this.addTime(this.WORK, t);
		}
		
		public function addRecoveryTime(t) {			
			return this.addTime(this.RECOVERY, t);
		}
		
		public function getRecoveryTimeInterval() {
			var dict = new Dictionary();
			for (var key in this.times) {
				if (this.times[key].type == this.RECOVERY) {
					dict[key] = this.times[key];
				}
			}
			return dict;
		}
		
		private function insertInterval(interval) {		
			if (this.times == null) {
				trace("time not defiened");
				return;
			}
			if (interval != null && interval.t0 != null && interval.te != null) {
				var stleft = 0;  // key (is string)
				var stright = 0; // key (is string)
				var tleft:Number = 0;
				var tright:Number = 0;
				var t0:Number = new Number(interval.t0);
				var te:Number = new Number(interval.te);
				//find left and right interval;
				var keys = Utils.dictKeys(this.times);					
				keys.sort(Array.NUMERIC);
				//for (var t in this.times) {
				for (var i = 0; i < keys.length;i++ ){
					if ( this.times[keys[i]].t0 > tleft && this.times[keys[i]].t0 <= t0) {
						tleft = this.times[keys[i]].t0;
						stleft = keys[i];
					}
					if ( (this.times[keys[i]].t0 > tright) && this.times[keys[i]].t0 <= te) {
						tright = this.times[keys[i]].t0;
						stright = keys[i];
					}
				}
		//		trace("tleft:" + stleft+"; t0:"+this.times[stleft].t0);
		//		trace("tright:" + stright+"; t0:"+this.times[stright].t0);
				this.times[t0] = interval;
				this.times[te] = { type:this.times[stright].type, t0:te, te:this.times[stright].te };
				if (tleft != tright) {
					delete this.times[tright];
					for (var t in this.times) { 
						var tn:Number = new Number(t);
						if (tn > t0 && tn < te) {
							delete this.times[t];
						}
					}
				}				
				this.times[stleft].te = t0;
			}			
		}
		
		private function refactorIntervals() {			
			var mod:Boolean = true;
			while (mod) {
				mod = false;
				var keys = Utils.dictKeys(this.times);
				keys.sort(Array.NUMERIC);
				for (var i = 1; i < keys.length; i++) {
					if(this.times[keys[i-1]] !=null && this.times[keys[i]]!=null){
						if (this.times[keys[i]].type == this.times[keys[i-1]].type) {
							mod = true;
							this.times[keys[i - 1]].te = this.times[keys[i]].te;
							delete this.times[keys[i]];
						}
						if (this.times[keys[i - 1]].t0 == this.times[keys[i - 1]].te ) {
							delete this.times[keys[i-1]];
						}
					}
				}
			}
		}
		
		public function unitRecoveryTime(tl:TimeLine) {
			if (tl != null) {
				var addIntervals = tl.getRecoveryTimeInterval();
				if(addIntervals !=null){
					for each(var interval in addIntervals) {						
						this.insertInterval(interval);						
					}
					this.refactorIntervals();
				}
			}			
		}
		
		public function getWorkTimeInterval() {
			var dict = new Dictionary();
			for (var key in this.times) {
				if (this.times[key].type == this.WORK) {
					dict[key] = this.times[key];
				}
			}
			return dict;
		}
		
		public function unitWorkTime(tl:TimeLine) {
			if (tl != null) {
				var addIntervals = tl.getWorkTimeInterval();
				if(addIntervals !=null){
					for each(var interval in addIntervals) {
						trace("   t0:" + interval.t0);
						trace("   te:" + interval.te);
						trace("   type:" + interval.type);						
						this.insertInterval(interval);
						trace("   .................");
					}
					this.refactorIntervals();
				}
			}
		}
		
		public function getKG() {
			var keys = Utils.dictKeys(this.times);
			keys.sort(Array.NUMERIC);
			var vsego = 0;
			var workT = 0;
			for (var i = 0; i < keys.length; i++) {
				if (this.times[keys[i]] != null) {
					if (this.times[keys[i]].type == this.WORK) {
						workT += this.times[keys[i]].te-this.times[keys[i]].t0;
					}
					vsego += this.times[keys[i]].te-this.times[keys[i]].t0;
				}
			}
			if (vsego > 0) {
				return workT / vsego;
			}
			return 0;
		}
		
		public function print() {
			if (times != null) {
				var keys = Utils.dictKeys(times);					
				keys.sort(Array.NUMERIC);
				var str = "";
				for (var i = 0 ; i < keys.length; i++ ) {
					str += "|" + times[keys[i]].t0 + "_" + times[keys[i]].type + "_" + times[keys[i]].te + "|";
				}
				trace(str);
			}			
		}
		
		public function getFirstWorkTime() {
			if (this.times != null && this.times[0]!=null) {
				return this.times[0].te;
			}
			return 0;
		}
		
		public function nowWork():Boolean {			
			var keys = Utils.dictKeys(times);					
			keys.sort(Array.NUMERIC);
			if(keys.length > 0){
				var el = this.times[keys[keys.length - 1]];
				if (el.type == this.WORK) return true;				
			}
			return false;
		}
		
	}
	
}